package base

/*************************************************
 *	@author zander
 *	@time 	2018年2月3日14:43:18
 *	@brief 	所有返回数据控制器
 *************************************************/

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"gopkg.in/mgo.v2/bson"
	"reflect"
	"time"
	"gitee.com/dayu1985/can_api/errors"

)



//不管返回正确或者返回错误，都可以交给他来执行
func Action(ctx *gin.Context,param interface{},fn func() (interface{},error)) {
	ctx.Set("logstart",time.Now().UnixNano())
	//1. 读取请求中的数据流
	data := getBodyData(ctx)

	if param != nil{
		if reflect.TypeOf(param).Kind() != reflect.Ptr || reflect.TypeOf(param).Elem().Kind() != reflect.Struct{
			panic("参数提必须为指针类型，指向一个struct")
		}

		//3. 读取请求中的数据
		initBodyData(ctx, data)
		err := ctx.BindJSON(param)
		if err != nil {
			Fail(ctx,errors.ParamDataNilErr())
			return
		}
		err = paramCheck(param)
		if err != nil{
			Fail(ctx,err)
			return
		}

	}else {
		initBodyData(ctx, data)
	}

	obj,err := fn()
	if err != nil {
		Fail(ctx,err)
		return
	}
	Success(ctx,obj)
	return
}

//进行参数检查，判断tag中的ck属性
//1. 只能验证单层的struct对象，也就是说对象中不能再包含struct对象
func paramCheck(obj interface{}) error{
	ty := reflect.TypeOf(obj)
	vl := reflect.ValueOf(obj)
	if ty.Kind() == reflect.Ptr {
		ty = ty.Elem()
		vl = vl.Elem()
	}

	if ty.Kind() == reflect.Struct {
		for i := 0; i < ty.NumField(); i++{
			t := ty.Field(i).Type
			tg := ty.Field(i).Tag
			v := vl.Field(i)
			if tg.Get("ck") == "ck"{
				switch t.Kind() {
				case reflect.Ptr:
					if v.Pointer() == 0 {
						return errors.ParamFieldNilErr(obj)
					}
				case reflect.String:
					if v.String() == "" {
						return errors.ParamFieldNilErr(obj)
					}
				}
			}
		}
	}
	return nil
}

//请求成功后返回
func Success(ctx *gin.Context, obj ... interface{}) {
	switch len(obj) {
	case 0:
		Result(ctx,0,"ok","Success")
	case 1:
		Result(ctx,0,"ok",obj[0])
	default:
		Result(ctx,0,"ok",obj)
	}
}

//请求失败后返回
func Fail(ctx *gin.Context, err interface{}) {
	ty := reflect.TypeOf(err)
	if err != nil && ty.Kind() == reflect.Struct && ty.Name() == "Exception" {
		excep,ok := err.(errors.Exception)
		if ok{
			res := excep.Response
			ty = reflect.TypeOf(res)
			vl := reflect.ValueOf(res)
			if ty.Kind() == reflect.Slice {
				if vl.Len() > 0 {
					excep.Response = vl.Index(0).Interface()
				}
			}
		}
		Result(ctx,excep.Code,excep.Message,excep.Response)
		return
	}

	Result(ctx,99999,"异常未识别错误",err)
	return
}

func Result(c *gin.Context,code int,msg string,res interface{}) {
	r := bson.M{
		"Code":     code,
		"Message":  msg,
		"Response": res,
	}
	//ApiOut(c,r)
	c.JSON(http.StatusOK, r)
}

func ApiIn(c *gin.Context,body map[string]interface{}) {

}

func ApiOut(c *gin.Context,resu interface{}) {

}
